﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Citrix.XaAdminMobile.ViewModel;
using System.Diagnostics;

namespace Citrix.XaAdminMobile.ViewPhone
{
    /// <summary>
    /// Interaction logic for PhoneLayout.xaml
    /// </summary>
    public partial class PhoneLayout : UserControl
    {
        /// <summary>
        /// The navigation context is used to manage the lifetime of views.
        /// </summary>
        private class ViewNavContext
        {
            /// <summary>
            /// This activation function is called when the view-model associated with this nav
            /// context becomes active. The v-m and nav context are supplied as the input arguments,
            /// the output being an instance of the page/view to be displayed.
            /// </summary>
            public Func<IPage, ViewNavContext, UserControl> Activate
            {
                get;
                set;
            }

            /// <summary>
            /// Used to optionally cache the view instance for reuse in the nav context.
            /// </summary>
            public UserControl View
            {
                get;
                set;
            }
        }

        /// <summary>
        /// A map of v-m types to their matching navigation contexts.
        /// </summary>
        private Dictionary<Type, ViewNavContext> navContexts = new Dictionary<Type, ViewNavContext>();

        /// <summary>
        /// The current navigation context.
        /// </summary>
        private ViewNavContext currentNavContext = null;

        /// <summary>
        /// The root view-model object.
        /// </summary>
        private ViewModelManager vmRoot = null;

        /// <summary>
        /// A reference to the associated navigation manager for the phone layout.
        /// </summary>
        private PhoneNavigation navigation;

        /// <summary>
        /// Our handler for the weak ref event PhoneNavigation.PageChanged
        /// </summary>
        private EventHandler pageChangedHandler;

        /// <summary>
        /// Default ctor.
        /// </summary>
        public PhoneLayout()
        {
            SetupNavContexts();
            InitializeComponent();

            this.vmRoot = App.TypedApp.ViewModel;
            this.navigation = this.vmRoot.ActiveNavigation as PhoneNavigation;
            if (null != this.navigation)
            {
                this.pageChangedHandler = new EventHandler(Navigation_PageChanged);
                this.navigation.PageChanged += this.pageChangedHandler;
                ApplyView();
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        /// <summary>
        /// Our handler for the page being changed, used to trigger a swap to the appropriate
        /// view for the new page.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Navigation_PageChanged(object sender, EventArgs e)
        {
            ApplyView();
        }


        /// <summary>
        /// Changes the active view to the one needed to display the current page.
        /// </summary>
        private void ApplyView()
        {
            var page = this.navigation.CurrentPage;
            var pageType = page.GetType();
            ViewNavContext old = this.currentNavContext;

            if (this.navContexts.ContainsKey(pageType))
            {
                this.currentNavContext = this.navContexts[pageType];
                var view = this.currentNavContext.Activate(page, this.currentNavContext);
                view.DataContext = page;
                this.ContentTarget.Content = view;
            }
            else
            {
                Debug.Assert(false, "Unknown page type detected!");
                this.ContentTarget.Content = null;
            }
        }

        /// <summary>
        /// Creates all the navigation contexts that are used to create the views that match
        /// any given view-model that is set as the current page.
        /// </summary>
        /// <remarks>
        /// The longer lived views that are commonly used get cached. Other less used views get
        /// recreated on the fly.
        /// </remarks>
        private void SetupNavContexts()
        {
            this.navContexts[typeof(SessionsViewModel)] = new ViewNavContext
            {
                Activate = (page, thisRef) =>
                {
                    if (null == thisRef.View)
                    {
                        thisRef.View = new ViewCommon.SessionsView();
                    }
                    return thisRef.View;
                }
            };
            this.navContexts[typeof(ServersViewModel)] = new ViewNavContext
            {
                Activate = (page, thisRef) =>
                {
                    if (null == thisRef.View)
                    {
                        thisRef.View = new ViewCommon.ServersView();
                    }
                    return thisRef.View;
                },
            };
            this.navContexts[typeof(SettingsViewModel)] = new ViewNavContext
            {
                Activate = (page, thisRef) =>
                {
                    return new ViewCommon.SettingsView();
                }
            };
            this.navContexts[typeof(AddServerViewModel)] = new ViewNavContext
            {
                Activate = (page, thisRef) =>
                {
                    return new ViewCommon.AddServerView();
                }
            };
            this.navContexts[typeof(SessionViewModel)] = new ViewNavContext
            {
                Activate = (page, thisRef) =>
                {
                    return new SessionDetailsView();
                }
            };
            this.navContexts[typeof(ServerViewModel)] = new ViewNavContext
            {
                Activate = (page, thisRef) =>
                {
                    return new ServerDetailsView();
                }
            };
        }
    }
}
